package com.yirui.serialcomm.core.protocol;

import com.yirui.serialcomm.core.domain.SimpleSerialCommPacket;
import com.yirui.serialcomm.core.domain.StreamType;
import com.yirui.serialcomm.core.util.HexUtils;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioChannelOption;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.BindException;
import java.net.InetSocketAddress;

/**
 * 启动TCP服务
 * @author Dujie
 * @create 2025/8/5
 * @since 1.0.0
 */
@Slf4j
public class TcpBridgeServer extends AbstractServer{
    private ChannelHandlerContext channelHandlerContext;
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private Channel clientChannel;

    /**
     * 默认最大64k缓存空间
     */
    private int receiveBufferSize = 64*1024;
    /**
     * 缓存空间中最小与初始化倍数尺度
     */
    private int receiveBufferSizeScale=3;

    private int port;
    private InetSocketAddress targetHost;
    private BridgeMode bridgeMode;
    private Bootstrap bootstrap = new Bootstrap();
    private TcpBridgeServer(BridgeMode bridgeMode, int tcpPort) {
        this.port = tcpPort;
        this.bridgeMode = bridgeMode;

    }

    public TcpBridgeServer(int tcpPort) {
        this(BridgeMode.Server, tcpPort);
    }

    public TcpBridgeServer(String targetHost, int tcpPort, PortAllocator portAllocator) {
        this(BridgeMode.Client, tcpPort);
        this.targetHost = new InetSocketAddress(targetHost, tcpPort);
        this.port = portAllocator.getTcp();

    }

    @Override
    public void start() throws Exception {
        if(bridgeMode  == BridgeMode.Server){
            startServer();
        }else{
            startClient();
        }

    }

    private void startClient() {
        // 创建EventLoopGroup以处理客户端连接

        if(workerGroup == null|| workerGroup.isShutdown()) {
            workerGroup = new NioEventLoopGroup(); // 用于接受连接
        }

        bootstrap.group(workerGroup)
                // 使用NioSocketChannel来作为连接用的channel类
                .channel(NioSocketChannel.class)

                .option(NioChannelOption.SO_REUSEADDR, true)
                .option(NioChannelOption.SO_KEEPALIVE, true)
                //.option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                // 关键配置：禁用自动关闭
                .option(ChannelOption.AUTO_CLOSE, false)
                // 设置 SO_RCVBUF（接收缓冲区大小）
                //.option(ChannelOption.SO_RCVBUF, receiveBufferSize/4)
                //自适应接收缓存分配器
                //minimum太小导致包不完整问题
                //.option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(receiveBufferSize/(2*receiveBufferSizeScale), receiveBufferSize/(1*receiveBufferSizeScale), receiveBufferSize))//64k
                //.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, getConnectionTimeout())
                .handler(new ChannelInitializer<SocketChannel>() {

                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        pipeline.addLast(new ServerHandler());
                    }
                });


        bootstrap.remoteAddress(targetHost);

        connectTo(bootstrap);
    }

    private void connectTo(Bootstrap bootstrap){
        log.info("[TcpBridgeServer] 尝试连接目标地址{}", targetHost);
        //bootstrap.bind(port);
        try {
            clientChannel = bootstrap.connect(targetHost).sync().channel();
            // 保持程序运行
            //clientChannel.closeFuture().sync();
        } catch (InterruptedException e) {
            workerGroup.shutdownGracefully();
        }
//        future.addListener((ChannelFutureListener) future1 -> {
//            if (!future1.isSuccess()) {
//                //重连交给后端线程执行
//                future1.channel().eventLoop().schedule(() -> {
//                    log.info("连接服务端失败，8s后重连...");
//                    try {
//                        connectTo(bootstrap);
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
//                }, 8000, TimeUnit.MILLISECONDS);
//            } else {
//                log.info("建立连接，连接服务端成功！");
//            }
//        });
    }

    private void startServer() throws Exception{
        // 创建EventLoopGroup以处理客户端连接
        bossGroup = new NioEventLoopGroup(1); // 用于接受连接
        workerGroup = new NioEventLoopGroup(); // 用于处理已经被接受的连接
        ServerBootstrap b = new ServerBootstrap(); // 创建ServerBootstrap实例
        b.group(bossGroup, workerGroup) // 设置EventLoopGroup
                .channel(NioServerSocketChannel.class) // 使用NioServerSocketChannel作为服务端通道实现
                .childHandler(new ChannelInitializer<SocketChannel>() { // 设置通道的ChannelHandler链初始化器
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline p = ch.pipeline();
                        // 心跳：读空闲 40 分钟
//                        p.addLast(new IdleStateHandler(40, 0, 0, TimeUnit.MINUTES));
//                        p.addLast(new LineBasedFrameDecoder(1024));
//                        p.addLast(new StringDecoder()); // 添加解码器，将ByteBuf转换为String
//                        p.addLast(new StringEncoder()); // 添加编码器，将String转换为ByteBuf发送给客户端
                        p.addLast(new ServerHandler()); // 添加自定义的处理器
                    }
                })
                // 设置 SO_RCVBUF（接收缓冲区大小）
                .option(ChannelOption.SO_RCVBUF, receiveBufferSize/4)
                .option(ChannelOption.SO_BACKLOG, receiveBufferSize/4) // 设置TCP参数，如SO_BACKLOG等（此处为示例）
                //自适应接收缓存分配器
                //minimum太小导致包不完整问题
                .option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(receiveBufferSize/(2*receiveBufferSizeScale), receiveBufferSize/(1*receiveBufferSizeScale), receiveBufferSize))//64k
                .childOption(ChannelOption.SO_KEEPALIVE, true); // 设置保持活动连接状态选项（此处为示例）

        // 绑定端口并开始接收进来的连接，调用sync()方法阻塞等待直到绑定完成。
        try {
            b.bind(port).syncUninterruptibly();
        }catch (Exception e){
            if(e instanceof BindException){
                throw new BindException("本地绑定端口:"+port+"异常:"+e.toString());
            }
            throw e;
        }
        log.info("[TcpServer] Server startup successful，port = {}" , port);
        // 等待服务器socket关闭，在调用join()之后，所有I/O操作都将关闭。
        // f.channel().closeFuture().sync();
    }


    @Override
    public void stop() {
        log.info("TCP服务关闭");
        super.stop();

        try {
            if(channelHandlerContext != null){
                channelHandlerContext.close();
                channelHandlerContext = null;
            }
            if(clientChannel != null){
                clientChannel.close();
            }
            if(workerGroup != null) {
                workerGroup.shutdownGracefully(); // 关闭EventLoopGroup，释放所有资源。
            }
            if(bossGroup != null) {
                bossGroup.shutdownGracefully();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    @Override
    public void send(ByteBuf buffer) {
        if(bridgeMode == BridgeMode.Client){
            if(clientChannel == null){
                log.warn("暂时没有客户端连接到TCP服务!");
                return;
            }
            if (log.isDebugEnabled()) {
                log.debug("[TCP] 给地址:{}发送应答数据包: {}", clientChannel.remoteAddress(), HexUtils.toHexString(ByteBufUtil.getBytes(buffer)));
            }

            if(!clientChannel.isOpen()){
                //http协议需要执行重连处理
                try {
                    clientChannel=  bootstrap.connect().sync().channel();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            clientChannel.writeAndFlush(buffer);

        }else{
            if(channelHandlerContext == null){
                log.warn("暂时没有客户端连接到TCP服务!");
                return;
            }
            if (log.isDebugEnabled()) {
                log.debug("[TCP] 给地址:{}发送应答数据包: {}", channelHandlerContext.channel().remoteAddress(), HexUtils.toHexString(ByteBufUtil.getBytes(buffer)));
            }
            channelHandlerContext.writeAndFlush(buffer);
        }

    }


    public class ServerHandler extends SimpleChannelInboundHandler<ByteBuf> {

        @Override
        protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
            channelHandlerContext = ctx;

            byte[] buffer = ByteBufUtil.getBytes(msg);
            if(log.isDebugEnabled()) {
                log.debug("收到客户端 {} 数据: {}", ctx.channel().remoteAddress(), HexUtils.toHexString(buffer));
            }
            //ctx.writeAndFlush("ok\n");
            //收到tcp数据写入管道流，等待串口服务处理
            packByteTo(buffer);
            //TcpServer.this.getConnector().write(buffer, 0, buffer.length);

        }

        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            super.channelActive(ctx);
            channelHandlerContext = ctx;

        }

        // 异常处理
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            log.error("客户端连接异常: {}" , cause);
            ctx.close();
        }
    }

    /**
     *数据打包为TCP标记
     * @param buffer
     * @throws IOException
     */
    private void packByteTo(byte[] buffer) throws IOException {

        this.getConnector().write(packetParser.encode(new SimpleSerialCommPacket(StreamType.TCP, buffer)));
    }
}
